float4x4 World;
float4x4 View;
float4x4 Projection;

float Width;
float Height;
float Scale;
float3 LightDirection;
float3 LightColour;
float3 AmbientColour;

bool DrawGrid;

texture TerrainTex;
sampler2D TerrainSampler = sampler_state
{ 
	texture = <TerrainTex>;
};


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Base

struct BaseVertexShaderInput
{
    float4 Position : POSITION0;
    float2 UV : TEXCOORD0;
    float3 Normal : NORMAL0;
};

struct BaseVertexShaderOutput
{
    float4 Position : POSITION0;
    float2 UV : TEXCOORD0;
    float3 Normal : TEXCOORD1;
};

BaseVertexShaderOutput BaseVertexShaderFunction(BaseVertexShaderInput input)
{
    BaseVertexShaderOutput output;

    float4 worldPosition = mul(input.Position, World);
    float4 viewPosition = mul(worldPosition, View);
    
    output.Position = mul(viewPosition, Projection);
	output.UV = input.UV;
	output.Normal = mul(input.Normal, World);

    return output;
}

float4 BasePixelShaderFunction(BaseVertexShaderOutput input) : COLOR0
{
 	float4 terrain = tex2D(TerrainSampler, input.UV);

	float4 output = terrain;
	
	float3 normal = normalize(input.Normal);
	float3 lightDir = normalize(LightDirection);
	float3 lightMod = dot(normal, lightDir);

	lightMod.r = clamp(lightMod.r * LightColour.r, AmbientColour.r, 1);
	lightMod.g = clamp(lightMod.g * LightColour.g, AmbientColour.g, 1);
	lightMod.b = clamp(lightMod.b * LightColour.b, AmbientColour.b, 1);
 
	output *= float4(lightMod, 1);

    return output;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Grid

texture GridTex;
sampler2D GridSampler = sampler_state
{ 
	texture = <GridTex>;
};

texture HighlightTex;
sampler2D HighlightSampler = sampler_state
{
	texture = <HighlightTex>;
};

struct GridVertexShaderInput
{
    float4 Position : POSITION0;
    float2 UV : TEXCOORD0;
};

struct GridVertexShaderOutput
{
    float4 Position : POSITION0;
    float2 UV : TEXCOORD0;
};

GridVertexShaderOutput GridVertexShaderFunction(GridVertexShaderInput input)
{
    GridVertexShaderOutput output;

    float4 worldPosition = mul(input.Position, World);
    float4 viewPosition = mul(worldPosition, View);
    
    output.Position = mul(viewPosition, Projection);
	output.UV = input.UV;

    return output;

}

float4 GridPixelShaderFunction(GridVertexShaderOutput input) : COLOR0
{
	float4 tex = tex2D(GridSampler, input.UV);
	float2 inputScale = input.UV;
	inputScale.x /= Width;
	inputScale.y /= Height;
	float4 hl = tex2D(HighlightSampler, inputScale.xy);	
	
	float4 output = float4(0, 0, 0, 1.0f);

	if (hl.r || hl.g || hl.b)
	{
		hl.a = 0.15;
		output = hl;
		output += tex;
	}
	else
	{	
		if (!DrawGrid)
		{
			tex.a = 0;
		}
		output *= tex;
	}
	
    return output;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

technique Technique1
{
    pass Base
    {
	    VertexShader = compile vs_2_0 BaseVertexShaderFunction();
	    PixelShader = compile ps_2_0 BasePixelShaderFunction();
    }
        
    pass Grid
    {
	    VertexShader = compile vs_2_0 GridVertexShaderFunction();
	    PixelShader = compile ps_2_0 GridPixelShaderFunction();
    }
}